class GPS
{
private: tuple<int, int, int> Latitude;
	     tuple<int, int, int> Longitude;
public:
	GPS() {}
	GPS(tuple<int, int, int> lat, tuple<int, int, int> lon) : 
	                         Latitude(lat), Longitude(lon) {}
	string GetLatitude();
	string GetLongitude();
	bool operator<(const GPS& g) const;
	bool operator==(const GPS& g) const;
};

class Item
{
private:
	string Order{ "" };    // selts, näiteks värvulised
	string Family{ "" };   // sugukond, näiteks vintlased
	string Species{ "" };  // liik, näiteks metsvint
	char Category = 0;     // esinemise kategooria A, B, C, D, E (vt. originaali web-st)
	vector<tuple<variant<string, GPS>, year_month_day, hh_mm_ss<seconds>, optional<int>>> Observations{};
	     // This is a vector of tuples: 
	     // get<0> specifies the location as object of type variant<string, GPS> where string presents 
		 // the community and object from class GPS the location coordinates
		 // get<1> specifies the date of observation as object of type year_month_day
		 // get<2> specifies the time of obseravation as object of type hh_mm_ss<seconds>
	     // get<3> specifies the number of observed birds. nullopt means that the counting failed
	     // The size ov vector Observations may be any except 0.
public:
	Item() {}     
	operator Entry()  // operator function to cast an object of Item to object of Entry (see below)
	{
		return Entry(Order, Family, Species, Category, Observations);
	}
};

class Entry
{
private:
	string Order { "" };                         // As in class Item
	string Family { "" };                        // As in class Item
	string Species { "" };                       // As in class Item
	char Category = 0;                           // As in class Item
	vector<tuple<variant<string, GPS>, year_month_day, hh_mm_ss<seconds>, 
		        optional<int>>> Observations{};  // As in class Item
public:
	//
	// Constructors
	//
	Entry() {}
	Entry(string s1, string s2, string s3, char c, vector<tuple<variant<string, GPS>, year_month_day,
		hh_mm_ss<seconds>, optional<int>>> v) :
		Order(s1), Family(s2), Species(s3), Category(c)
	{
		Observations.resize(v.size());  
		ranges::copy(v, Observations.begin());
	}
	Entry(const Entry &Original);
	//
	// Accessor functions
	//
	string GetOrder();
	void SetOrder(string s);
	string GetFamily();
	void SetFamily(string s);
	string GetSpecies();
	void SetSpecies(string s);
	char GetCategory();
	void SetCategory(char c);
	vector<tuple<variant<string, GPS>, year_month_day, hh_mm_ss<seconds>, optional<int>>> GetObservations();
	void SetObservations(vector<tuple<variant<string, GPS>, year_month_day, hh_mm_ss<seconds>, optional<int>>> o);
	//
	// Operator functions
	//
	bool operator<(const Entry &) const; 
	Entry& operator=(const Entry& Right); 
	friend ostream& operator<<(ostream&, const Entry&);
};

class Data
{
private:
	map<string, map<string, set<Entry>>> *pDataStructure = nullptr;
	                                                        // It is a C++ map in which the Entry members Order are the keys. 
	                                                        // The values are inner C++ maps in which the keys are Entry members
															// Family  and the values are sets. The sets contain entries belonging
															// to the specified order and family.

	int nEntries = 0;                                       // total number of entries in DataStructure

public:
	Data();                                                 // constructor
	
	~Data();                                                // destructor

	int CountAllEntries();                                  // returns the total number of entries in DataStructure

	void PrintAll();                                        // prints all the entries that are currently stored in 
	                                                        // the DataStructure

	bool InsertEntry(Item *pI);                             // creates the entry and inserts into the data structure and
	                                                        // releases the memory of input value

	bool InsertEntries(initializer_list<Item *> items);     // creates the entries and inserts into the data structure and
	                                                        // releases the memory of input values

	void PrintEntries(string species) noexcept(false);      // prints all the entries presenting the given bird species 

	
	Entry* GetSummaryEntry(string species);                 // returns a new entry in which all the observations concerning 
	                                                        // the given bird species are combined into one vector

	list<Entry>* GetEntries(string species);                // returns the pointer to list containing all the entries
	                                                        // presenting the given bird species

	int CountEntries(string species);                       // returns the number of entites presenting the given bird species

	bool RemoveEntries(string species);                     // removes all the entries presenting the given bird species 

	void PrintFamilyEntries(string family) noexcept(false); // prints all the entries presenting the birds from the  
	                                                        // specified family
	 
	int CountFamilyEntries(string family);                  // returns the number of entites presenting the birds from the  
	                                                        // specified family

	bool RemoveFamilyEntries(string family);                // removes all the entities presenting the birds from the  
	                                                        // specified family

	void PrintOrderEntries(string order) noexcept(false);  // prints all the entries presenting the birds from the  
	                                                       // specified order

	int CountOrderEntries(string order);                   // returns the number of entites presenting the birds from the  
	                                                       // specified order

	bool RemoveOrderEntries(string order);                 // removes all the entities  presenting the birds from the  
	                                                       // specified order
};



